package sample;

import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;

public class MethodModificationExample {
    private static String[] toStringArray(List<?> l) {
        if (l.isEmpty())
            return null;

        //noinspection RedundantCast,unchecked
        return ((List<String>) l).toArray(new String[l.size()]);
    }


    public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        // 1. 创建一个ClassReader来读取现有类的字节码
        ClassReader classReader = new ClassReader("sample.TestClass");

        // 2. 创建一个ClassWriter用于生成修改后的类
        ClassWriter classWriter = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS);

        // 3. 创建一个ClassVisitor，它将访问并修改类的结构
        ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM7, classWriter) {
            MethodNode methodNode;

            @Override
            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                // 4. 在这里检查需要修改的方法
                if (name.equals("test1")) {
                    // 5. 修改方法的参数描述符
//                        methodNode = new MethodNode(access, name, "(I)V", signature, exceptions);
                    methodNode = new MethodNode(access, name, desc, signature, exceptions);
                    return methodNode;
                }
                return super.visitMethod(access, name, desc, signature, exceptions);
            }

            @Override
            public void visitEnd() {

                MethodVisitor outMV = super.visitMethod(methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, toStringArray(methodNode.exceptions));
//                methodNode.accept(outMV);
                new InstrumentMethod(methodNode).accept(outMV);

            }


        };

        // 9. 开始访问并修改类
        classReader.accept(classVisitor, 0);

        // 10. 生成修改后的类
        byte[] modifiedClass = classWriter.toByteArray();

        // 11. 将修改后的类写入文件或加载到类加载器
        try (FileOutputStream fos = new FileOutputStream("TestClass.class")) {
            fos.write(modifiedClass);
        }
        MyClassLoader classLoader = new MyClassLoader();
        Class<?> clazz = classLoader.defineClass("sample.TestClass", modifiedClass);
        Object obj = clazz.newInstance();
        clazz.getMethod("test1").invoke(obj);
        clazz.getMethod("test1").invoke(obj);
        clazz.getMethod("test1").invoke(obj);
        clazz.getMethod("test1").invoke(obj);
        clazz.getMethod("test1").invoke(obj);

    }
}
